package lt.mii.optimum.components;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import lt.mii.optimum.Start;
import lt.mii.optimum.io.XmlFileOut;

/**
 * Class represents one Day of the week.<br>
 * Contains some amount of {@link Flow}s <br>
 * 
 * @author dstrukov
 * 
 */
public class Day implements Comparable<Day> {

	/**
	 * Maximum possible flows per day. Restricted to maximum of 24 a day.
	 */
	static int MAX_FLOWS_PER_DAY = 24;

	/**
	 * Name of the day.
	 */
	private Days $day;
	/**
	 * List of flows this day.
	 */
	private List<Flow> $flows;



	/**
	 * Constructor
	 * 
	 * @param day -
	 *            Name of the day
	 */
	public Day(Days day) {
		$day = day;
		$flows = new ArrayList<Flow>();
	}



	/**
	 * Adds a single {@link Flow} to the day.
	 * 
	 * @param priority
	 *            Subjects of which priority to compile
	 * @return Returns false if failed to compile the flow
	 */
	public boolean addFlow(int priority) {
		boolean flag = false;
		for (Flow flow : $flows) {
			if (flow.compile(priority)) {
				flag = true;

			}
		}
		if (!flag) {
			Flow flow = new Flow(this);
			if (flow.compile(priority)) {
				$flows.add(flow);
				return true;
			}
		}
		return false;
	}



	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Day other = (Day) obj;
		if ($day != other.$day)
			return false;
		return true;
	}



	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + $day.getNr();
		return result;
	}



	/**
	 * Print content of the day to given output
	 * 
	 * @param out -
	 *            {@link XmlFileOut} desired XML file output
	 */
	public void output(XmlFileOut out) {

		Iterator<Flow> it = $flows.iterator();
		while (it.hasNext()) {
			out.startRow();
			Flow f = it.next();
			out.addTag(f.getId().toString());
			f.output(out);
			out.endRow();
		}

	}



	@Override
	public String toString() {
		String ret = "";
		Iterator<Flow> it = $flows.iterator();
		while (it.hasNext()) {
			Flow f = it.next();
			Iterator<Person> tit = f.getPersonList().iterator();
			while (tit.hasNext()) {
				Person t = tit.next();
				if (t instanceof Teacher) {
					Teacher teach = (Teacher) t;
					ret += "[" + teach.toString() + "] ";
				}
			}
			ret += '\n';
		}

		return $day.toString();
	}



	/**
	 * Calculates amount of gaps between {@link Teacher} lessons.
	 * 
	 * @return Returns <code>int</code> amount of windows.
	 */
	public int TeacherWindows() {
		int count = 0;
		Iterator<Teacher> it = Start.data.getTeachers().iterator();
		while (it.hasNext()) {
			// System.out.println("----------------------------------");
			Teacher teach = it.next();

			Iterator<Flow> fit = $flows.iterator();
			boolean enter = false;
			boolean exit = false;
			int tempCount = 0;
			while (fit.hasNext()) {
				Flow flow = fit.next();

				if (flow.getPersonList().contains(teach)) {
					// System.out.println("yes");
					enter = true;
					if (exit) {
						count += tempCount;
						tempCount = 0;
						exit = false;
					}
				} else {
					// System.out.println("no");

					if (enter) {
						tempCount++;
						exit = true;
					}

				}
			}

		}

		return count;
	}



	/**
	 * Calculates amount of gaps between {@link Student} lessons.
	 * 
	 * @return Returns <code>int</code> amount of windows.
	 */
	public int StudentWindows() {
		int count = 0;
		Iterator<Student> it = Start.data.getStudents().iterator();
		while (it.hasNext()) {
			// System.out.println("----------------------------------");
			Student stud = it.next();

			Iterator<Flow> fit = $flows.iterator();
			boolean enter = false;
			boolean exit = false;
			int tempCount = 0;
			while (fit.hasNext()) {
				Flow flow = fit.next();

				if (flow.getPersonList().contains(stud)) {
					// System.out.println("yes");
					enter = true;
					if (exit) {
						count += tempCount;
						tempCount = 0;
						exit = false;
					}
				} else {
					// System.out.println("no");

					if (enter) {
						tempCount++;
						exit = true;
					}

				}
			}

		}

		return count;
	}



	/**
	 * 
	 * @return Returns All flows from current Day
	 */
	public List<Flow> getFlows() {
		return $flows;
	}



	/**
	 * 
	 * @return Returns name of the day
	 */
	public Days getDay() {
		return $day;
	}



	@Override
	public int compareTo(Day o) {
		if (this.$day.getNr() == o.getDay().getNr())
			return 0;
		if (this.$day.getNr() > o.getDay().getNr())
			return 1;
		assert this.$day.getNr() < o.getDay().getNr();

		return -1;

	}
}
